package com.framework.auth.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.framework.common.model.*;
import com.framework.auth.mapper.SysMenuMapper;
import com.framework.auth.mapper.SysUserMapper;
import com.framework.auth.model.CustomUser;
import com.framework.auth.service.IUserService;
import com.framework.common.constants.FieldConstant;
import com.framework.common.exception.BusinessException;
import com.framework.common.util.StringUtils;
import com.framework.common.vo.TreeNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserService implements IUserService {
    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    @Transactional(rollbackOn = Exception.class)
    public CustomUser getCustomUserByUserName(String userName) {
        UserInfo userInfo = getUserInfoByUserName(userName);
        if (StringUtils.isEmpty(userInfo)) {
            throw new UsernameNotFoundException("用户名错误");
        }
        List<GrantedAuthority> authorities = userInfo.getAuthCodes()
                .stream()
                .map(it -> new SimpleGrantedAuthority(it)).collect(Collectors.toList());
        // 新版这里没有有问题可以传 第三个参数， 不会导致jwt太长
        return new CustomUser(userInfo.getSysUser(), userInfo, authorities);
    }

    @Override
    public boolean exists(String userName) {
        int len = sysUserMapper.exists(userName);
        return len > 0;
    }

    @Override
    @Transactional(rollbackOn = Exception.class)
    public UserInfo getUserInfoByUserName(String userName) {
        CommonUser commonUser = sysUserMapper.findByAccount(userName);
        return getUserInfo(commonUser);
    }

    private UserInfo getUserInfo(CommonUser commonUser) {
        if (StringUtils.isEmpty(commonUser)) {
            return null;
        }
        List<CommonRole> roles = sysUserMapper.findRoleByUserId(commonUser.getId());
        Set<String> roleIds = roles.stream().map(CommonRole::getId).collect(Collectors.toSet());

        UserInfo userInfo = new UserInfo();
        userInfo.setSysUser(commonUser);
        List<TreeNode<CommonMenu>> menuList;
        if (CollectionUtil.isEmpty(roleIds)) {
            throw new BusinessException("该用户未配置任何角色,无法进行登录操作!");
        }
        Set<String> authCodes = new HashSet<>();
        // 管理员可以访问所有菜单
        if (hasSuperAdminRole(roles)) {
            menuList = getMenuTree(new HashSet<>(), authCodes);
        } else {
            menuList = getMenuTree(roleIds, authCodes);
        }
        userInfo.setMenuList(menuList);
        userInfo.setAuthCodes(new ArrayList<>(authCodes));
        Set<CommonRole> set = new HashSet<>(roles);
        userInfo.setRoles(set);
        String strDeptIds = commonUser.getDeptId();
        if (StringUtils.isNotBlank(strDeptIds)) {
            String[] deptIds = strDeptIds.split(",");
            List<CommonDept> depts = sysUserMapper.findUserDept(Arrays.asList(deptIds));
            userInfo.setDepts(new HashSet<>(depts));
        }

        // 更新最后登录时间
        sysUserMapper.updateLoginTime(commonUser.getId());

        return userInfo;
    }

    /**
     * 判断是否有管理员角色
     *
     * @param roles
     * @return 判断是否有管理员角色
     */
    public boolean hasSuperAdminRole(List<CommonRole> roles) {
        for (CommonRole role : roles) {
            if (role.getIsSuperAdmin() != null &&
                    role.getIsSuperAdmin() == 1) {
                return true;
            }
        }

        return false;
    }

    private List<TreeNode<CommonMenu>> getMenuTree(Set<String> roleIds, Set<String> authCodes) {
        Map<String, Object> params = new HashMap<>(16);
        params.put("roleIds", roleIds);
        List<CommonMenu> list;
        if (roleIds.size() > 0) {
            list = sysMenuMapper.findMenu(params);
        } else {
            list = sysMenuMapper.findMenuAll(params);
        }

        List<String> codes = list.stream().map(o -> o.getCode()).collect(Collectors.toList());
        authCodes.addAll(codes);
        list = list.stream().filter(o -> !FieldConstant.BUTTON.equals(o.getType())).collect(Collectors.toList());
        List<CommonMenu> topList = list.stream().filter(o -> FieldConstant.ROOT.equals(o.getPcode())).collect(Collectors.toList());
        list.removeAll(topList);
        List<TreeNode<CommonMenu>> parents = new ArrayList<>();
        setChildren(topList, list, parents);
        return parents;
    }

    private void setChildren(List<CommonMenu> topList, List<CommonMenu> allList, List<TreeNode<CommonMenu>> treeNode) {
        topList.forEach(o -> {
            TreeNode<CommonMenu> child = new TreeNode();
            child.setId(o.getId());
            child.setPid(o.getPcode());
            child.setName(o.getName());
            child.setData(o);
            treeNode.add(child);
            List<CommonMenu> children = allList.stream().filter(c -> o.getCode().equals(c.getPcode())).collect(Collectors.toList());
            if (children.size() > 0) {
                allList.removeAll(children);
                child.newChildren();
            }
            setChildren(children, allList, child.getChildren());
        });
    }
}
